'''
Created on 14/07/2010

@author: eh01
'''
from datastore.uri import Uri
from runtime.service import Service
from datastore.resource import Resource
from spear.a2p_service import A2PServiceAPI
from datastore.spaces import Spaces

class AcceptRejectService(Service):
    
    OUTCOME = 'outcome'
    OUTCOME_ACCEPT = 'accept'
    OUTCOME_ACCEPT_WITH_CHANGES = 'acceptwithchanges'
    OUTCOME_REJECT = 'reject'
    SPEAR_REF = 'spearRef'
    OPERATION = 'operation'
    OK = 'OK'
    CANCEL = 'Cancel'
    RESPONSE = 'response'
    EXISTS = 'exists'
    REASON = 'reason'
    
    def cb_start(self, uri, action, res):
        self.spaces.set_process(Uri('internal:adaptor/accept-reject/'), self.cb_accept_reject_application)
        self.spaces.set_process(Uri('internal:adaptor/accept-reject/reject/'), self.cb_reject_application)
        
    def cb_accept_reject_application(self, uri, action, res):
        if uri.split()[-1] == AcceptRejectService.RESPONSE:
            # we are not doing anything with the response so we can safely ignore it. 
            return        
        if action == Spaces.ACTION_PUT:
            if res.form_fields:
                # get the form data
                form_data = {}
                for key in res.form_fields.keys():
                    form_data[key] = str(res.form_fields[key])
                operation = form_data[AcceptRejectService.OPERATION]
                spear_reference = form_data[AcceptRejectService.SPEAR_REF]                
                # user pressed OK
                if operation == AcceptRejectService.OK:
                    # if OK is clicked then handle the outcome appropriately
                    if AcceptRejectService.OUTCOME in form_data:                                
                        outcome = form_data[AcceptRejectService.OUTCOME]
                        if outcome == AcceptRejectService.OUTCOME_REJECT:
                            # redirect to the reject reason UI
                            redirect_url = '/adaptor/accept-reject/reject?spearRef=%s' % spear_reference
                        elif outcome == AcceptRejectService.OUTCOME_ACCEPT:
                            # issue accept instr to SPEAR
                            redirect_url = '/adaptor/application?spearRef=%s' % spear_reference
                        elif outcome == AcceptRejectService.OUTCOME_ACCEPT_WITH_CHANGES:
                            # issue accept with changes instr to SPEAR
                            redirect_url = '/adaptor/application?spearRef=%s' % spear_reference
                    
                        # create the response resource to force a redirect
                        headers = {'Location':redirect_url}
                        response_rs = self.create_response_resource(None, None, 302, headers)
                        response_uri = uri + AcceptRejectService.RESPONSE                            
                    else:
                        # if no outcome is selected, then raise a error
                        user_list = self.get_spear_user_list(self.spaces)
                        # create the VO to return to the view
                        response_rs =  Resource(type="term:eplanning/adaptor/acceptreject/get/data")
                        response_rs.h1_header = "Accept or Reject Application"
                        response_rs.validation_error = True
                        response_rs.user_list = user_list
                        response_rs.spear_ref = spear_reference
                        response_uri = uri + AcceptRejectService.RESPONSE
                # user pressed cancel                                
                else:
                    # if cancel press, then redirect to app screen
                    redirect_url = '/adaptor/application?spearRef=%s' % spear_reference
                        
                    # create the response resource to force a redirect                    
                    headers = {'Location':redirect_url}
                    response_rs = self.create_response_resource(None, None, 302, headers)
                    response_uri = uri + AcceptRejectService.RESPONSE
            else:
                # get the query data. This handles the GET with query parameters scenario.
                query_data = {}
                for key in res.query_data.keys():
                    query_data[key] = str(res.query_data[key])
                spear_reference = query_data[AcceptRejectService.SPEAR_REF]
                
                # retreieve the user list
                user_list = self.get_spear_user_list(self.spaces)
                
                # create the VO to return to the view
                response_rs =  Resource(type="term:eplanning/adaptor/acceptreject/get/data")
                response_rs.h1_header = "Accept or Reject Application"
                response_rs.user_list = user_list
                response_rs.spear_ref = spear_reference
                response_uri = uri + AcceptRejectService.RESPONSE      
            self.spaces.put(response_uri, response_rs)
            return response_uri     
        elif action == Spaces.ACTION_EXISTS:
            # by returning False and implying that the resource does not exist at this location, 
            # we force spaces to call the callback with the action "put" instead of "update" in the
            # 'put' method in spaces.
            return False
        else:
            return
    
    def cb_reject_application(self, uri, action, res):
        if uri.split()[-1] == AcceptRejectService.RESPONSE:
            # we are not doing anything with the response so we can safely ignore it. 
            return        
        if action == Spaces.ACTION_PUT:
            if res.form_fields:
                # get the form data
                form_data = {}
                for key in res.form_fields.keys():
                    form_data[key] = str(res.form_fields[key])                
                spear_reference = form_data[AcceptRejectService.SPEAR_REF]
                operation = form_data[AcceptRejectService.OPERATION]
                # user pressed OK
                if operation == AcceptRejectService.OK:
                    if AcceptRejectService.REASON in form_data:
                        reason = form_data[AcceptRejectService.REASON]
                        
                        self.do_accept_reject_application(self.spaces, spear_reference, reason)                        
                        # create the response resource to force a redirect
                        headers = {'Location':'/adaptor/application?spearRef=%s' % spear_reference}
                        response_rs = self.create_response_resource(None, None, 302, headers)                        
                        response_uri = uri + AcceptRejectService.RESPONSE         
                    else:
                        # create the VO to return to the view
                        response_rs =  Resource(type="term:eplanning/adaptor/acceptreject/reject/get/data")
                        response_rs.h1_header = "Reject Application Reason"
                        response_rs.spear_ref = spear_reference
                        response_rs.validation_error = True
                        response_uri = uri + AcceptRejectService.RESPONSE
                # user pressed cancel                                
                else:
                    # do nothing if Cancel pressed.

                    # create the response resource to force a redirect
                    headers = {'Location':'/adaptor/application?spearRef=%s' % spear_reference}
                    response_rs = self.create_response_resource(None, None, 302, headers) 
                    response_uri = uri + AcceptRejectService.RESPONSE                
            else:
                # get the query data. This handles the GET with query parameters scenario.
                query_data = {}
                for key in res.query_data.keys():
                    query_data[key] = str(res.query_data[key])
                spear_reference = query_data[AcceptRejectService.SPEAR_REF]
                
                # create the VO to return to the view
                response_rs =  Resource(type="term:eplanning/adaptor/acceptreject/reject/get/data")
                response_rs.h1_header = "Reject Application Reason"
                response_rs.spear_ref = spear_reference
                response_uri = uri + AcceptRejectService.RESPONSE        
            self.spaces.put(response_uri, response_rs)
            return response_uri        
        elif action == Spaces.ACTION_EXISTS:
            # by returning False and implying that the resource does not exist at this location, 
            # we force spaces to call the callback with the action "put" instead of "update" in the
            # 'put' method in spaces.
            return False
        else:
            return

    def get_spear_user_list(self, spaces):
        """
        Retrieves the the spear user list for the current responsible authority. 
        
        :param spaces: Instance of spaces.         
        :rtype: List of dictionaries, where each dictionary defines attributes (e.g first name, last name ...) of a user.
        """        
        a2p_service_api = A2PServiceAPI(spaces)
        spear_user_list_resp_rs = a2p_service_api.get_user_list()
        user_list_uri = spear_user_list_resp_rs.get_var('a2p:user-list/uri')
        spear_user_list_rs = spaces.get(user_list_uri)
        user_list = spear_user_list_rs.user_list
        return user_list
    
    def do_accept_reject_application(self, spaces, spear_reference, reason):
        a2p_service_api = A2PServiceAPI(spaces)
        rs = a2p_service_api.send_acceptreject_application(spear_reference, acceptreject_flag=A2PServiceAPI.ACCEPTREJECT_REJECT, reject_reason=reason)
        rs.get_var(Uri('a2p:request/uri'))
                
    def create_response_resource(self, content, content_type, status, headers):
        """
        Creates a response resource. 
        
        :param content: content of response as a string.
        :param content_type: content type of the response (e.g. text/xml) as a string.
        :param status: http status code as a int (e.g 200).
        :param headers: headers for the response as a dictionary where the key is a header field and the value is the value of the header field.
        :rtype: resource of type='term:base/services/http/response'
        """          
        response_rs = Resource(type='term:base/services/http/response')
        response_rs.content = content
        response_rs.content_type = content_type
        if response_rs.content:
            response_rs.content_length = len(response_rs.content)
        else:
            response_rs.content_length = 0
        response_rs.status = status
        response_rs.headers = headers
        return response_rs